package tailorbird.util.security;

import java.security.Key;
import java.security.Provider;
import java.security.Security;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;

import org.apache.log4j.Logger;

import tailorbird.util.arrays.Arrayor;
import tailorbird.util.string.Stringor;

/**
 * @author marvy
 */
public class StandardJCEDESHandler {

	public static final String ALG_DES = "DES";
	private static final Logger logger = Logger
			.getLogger(StandardJCEDESHandler.class);

	public static void main(String[] args) {

		String data = "9629980200000003";
		String keyData = "3131313131313131";
		StandardJCEDESHandler handler = new StandardJCEDESHandler();

		byte[] enData = null;
		byte[] deData = null;
		try {
			Key key = StandardJCEHandlerUtil.getSecretKey(Stringor
					.getBytes(keyData));

			enData = handler.encryptData(Stringor.getBytes(data), key);
			System.out.println(Arrayor.hexString(enData));
			deData = handler.decryptData(enData, key);

			System.out.println(new String(deData));
		} catch (JCEHandlerException e) {
			logger.debug(e.getMessage(), e);
		}
	}

	// The JCE provider
	Provider provider = null;

	public StandardJCEDESHandler() {

		this(new com.sun.crypto.provider.SunJCE());
	}

	public StandardJCEDESHandler(Provider provider) {

		this.provider = provider;
		Security.addProvider(provider);
	}

	public StandardJCEDESHandler(String jceProviderClassName)
			throws JCEHandlerException {

		try {
			provider = (Provider) Class.forName(jceProviderClassName)
					.newInstance();
			Security.addProvider(provider);
		} catch (Exception e) {
			throw new JCEHandlerException(e);
		}
	}

	public byte[] decryptData(byte[] encryptedData, Key key)
			throws JCEHandlerException {

		byte[] clearData;
		clearData = doCryptStuff(encryptedData, key, Cipher.DECRYPT_MODE);
		return clearData;
	}

	public Key decryptDESKey(byte[] encryptedDESKey, Key encryptingKey,
			boolean checkParity) throws JCEHandlerException {

		Key key = null;
		byte[] clearKeyBytes = doCryptStuff(encryptedDESKey, encryptingKey,
				Cipher.DECRYPT_MODE);
		if (checkParity) {
			if (!JCEUtil.isDESParityAdjusted(clearKeyBytes)) {
				throw new JCEHandlerException("Parity not adjusted");
			}
		}
		key = new SecretKeySpec(clearKeyBytes, ALG_DES);
		return key;
	}

	public byte[] encryptData(byte[] data, Key key) throws JCEHandlerException {

		byte[] encryptedData;
		encryptedData = doCryptStuff(data, key, Cipher.ENCRYPT_MODE);
		return encryptedData;
	}

	public Key generateDESKey() throws JCEHandlerException {

		Key generatedClearKey = null;
		try {
			KeyGenerator k1 = KeyGenerator.getInstance(ALG_DES, provider
					.getName());
			generatedClearKey = k1.generateKey();
		} catch (Exception e) {
			if (e instanceof JCEHandlerException)
				throw (JCEHandlerException) e;
			else
				throw new JCEHandlerException(e);
		}
		return generatedClearKey;
	}

	byte[] doCryptStuff(byte[] data, Key key, int CipherMode)
			throws JCEHandlerException {

		byte[] result;
		String transformation = key.getAlgorithm();
		try {
			Cipher c1 = Cipher.getInstance(transformation);
			c1.init(CipherMode, key);
			result = c1.doFinal(data);
		} catch (Exception e) {
			throw new JCEHandlerException(e);
		}
		return result;
	}
}
